/*
 * @Author: 赵东选 1807248216@qq.com
 * @Date: 2024-10-20 10:06:05
 * @LastEditors: 赵东选 1807248216@qq.com
 * @LastEditTime: 2024-10-26 13:32:32
 * @FilePath: /9_int/project/start.s
 * @Description:
 *
 * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
 */
.global _start


_start:

    /* 设置中断 */
    ldr pc, =Reset_Handler		/* 复位中断 					*/	
	ldr pc, =Undefined_Handler	/* 未定义中断 					*/
	ldr pc, =SVC_Handler		/* SVC(Supervisor)中断 		*/
	ldr pc, =PrefAbort_Handler	/* 预取终止中断 					*/
	ldr pc, =DataAbort_Handler	/* 数据终止中断 					*/
	ldr	pc, =NotUsed_Handler	/* 未使用中断					*/
	ldr pc, =IRQ_Handler		/* IRQ中断 				*/
	ldr pc, =FIQ_Handler		/* FIQ(快速中断) 	*/
    
/* 复位中断函数 */
Reset_Handler:
    
    cpsid i     /* 关闭全局中断 */

    /* 关闭I,DCache和MMU 
	 * 采取读-改-写的方式。
	 */
    MRC p15,0,r0,c1,c0,0     /* 读取CP15的C1寄存器到R0中 */

    bic r0,r0,#(0x1 << 12)      /* 清除C1寄存器的bit12位(I位)，关闭I Cache */
    bic r0,r0,#(0x1 << 11)      /* 清除C1寄存器的bit11(Z位)，关闭分支预测 */
    bic r0,r0,#(0x1 << 2)       /* 清除C1寄存器的bit2(C位)，关闭D Cache */
    bic r0,r0,#(0x1 << 1)       /* 清除C1寄存器的bit1(A位)，关闭对齐 */
    bic r0,r0,#(0x1 << 0)       /* 清除C1寄存器的bit0(M位)，关闭MMU */
    
    MCR p15,0,r0,c1,c1,0     /* 将r0寄存器中的值写入到CP15的C1寄存器中	*/

#if 0
    /* 汇编版本设置中断向量表偏移 */
    ldr r0,=0x87800000
    DSB
    ISB
    MCR p15,0,r0,c12,c0,0
    DSB
    ISB
#endif


.global _bss_start
_bss_start:
    .word __bss_start

.global _bss_end
_bss_end:
    .word __bss_end

    /* 清除BSS段 */
    ldr r0, =_bss_start
    ldr r1, =_bss_end
    mov r2, #0
bss_loop:
    stmia r0!, {r2}
    cmp r0, r1
    ble bss_loop

    /* 设置处理器进入IRQ模式 */
    mrs r0, cpsr
    bic r0, r0, #0x1f
    orr r0, r0, #0x12
    msr cpsr, r0
    /* 设置SP指针 */
    ldr sp, =0x80600000

    /* 设置处理器进入SYS模式 */
    mrs r0, cpsr
    bic r0, r0, #0x1f
    orr r0, r0, #0x1f
    msr cpsr, r0
    /* 设置SP指针 */
    ldr sp, =0x80400000

    /* 设置处理器进入SVC模式 */
    mrs r0, cpsr
    bic r0, r0, #0x1f
    orr r0, r0, #0x13
    msr cpsr, r0
    /* 设置SP指针 */
    ldr sp, =0x80200000

    CPSIE i     /* 打开全局中断 */
    b main
    
/* 未定义中断函数 */
Undefined_Handler:
    ldr r0 ,=Undefined_Handler
    bx r0

/* SVC(Supervisor)中断函数 */
SVC_Handler:
    ldr r0 ,=SVC_Handler
    bx r0

/* 预取终止中断函数 */
PrefAbort_Handler:
    ldr r0 ,=PrefAbort_Handler
    bx r0

/* 数据终止中断函数 */
DataAbort_Handler:
    ldr r0 ,=DataAbort_Handler
    bx r0
    
/* 未使用中断函数 */
NotUsed_Handler:
    ldr r0 ,=NotUsed_Handler
    bx r0

/* IRQ中断函数 */
IRQ_Handler:
	push {lr}					/* 保存lr地址 */
	push {r0-r12}			    /* 保存r0-r3，r12寄存器 */

	mrs r0, spsr				/* 读取spsr寄存器 */
	push {r0}					/* 保存spsr寄存器 */

	mrc p15, 4, r1, c15, c0, 0 /* 从CP15的C0寄存器内的值到R1寄存器中
								* 参考文档ARM Cortex-A(armV7)编程手册V4.0.pdf P49
								* Cortex-A7 Technical ReferenceManua.pdf P68 P138
								*/							
	add r1, r1, #0X2000			/* GIC基地址加0X2000，也就是GIC的CPU接口端基地址 */
	ldr r0, [r1, #0XC]			/* GIC的CPU接口端基地址加0X0C就是GICC_IAR寄存器，
								 * GICC_IAR寄存器保存这当前发生中断的中断号，我们要根据
								 * 这个中断号来绝对调用哪个中断服务函数
								 */
	push {r0, r1}				/* 保存r0,r1 */
	
	cps #0x13					/* 进入SVC模式，允许其他中断再次进去 */
	
	push {lr}					/* 保存SVC模式的lr寄存器 */
	ldr r2, =system_irqhandler	/* 加载C语言中断处理函数到r2寄存器中*/
	blx r2						/* 运行C语言中断处理函数，带有一个参数，保存在R0寄存器中 GICC_IAR寄存器 */

	pop {lr}					/* 执行完C语言中断服务函数，lr出栈 */
	cps #0x12					/* 进入IRQ模式 */
	pop {r0, r1}				
	str r0, [r1, #0X10]			/* 中断执行完成，写GICC_EOIR */

	pop {r0}						
	msr spsr_cxsf, r0			/* 恢复spsr */

	pop {r0-r12}			    /* r0-r3,r12出栈 */
	pop {lr}					/* lr出栈 */
	subs pc, lr, #4             /* 将lr-4赋给pc */
    
/* FIQ(快速中断)函数 */
FIQ_Handler:
    ldr r0 ,=FIQ_Handler
    bx r0
